import genTokenUtil from "@/views/FormGenerator/util/genCode/warpToken";
import { getFieldConfig } from "@/components/RuntimeComp";
import { genCompPropStr } from "@/views/FormGenerator/util/genCode";
import {
  isTableHelperColumn,
  getFieldDefaultValue,
  genFieldMapField,
} from "@/utils";

const functionStrReg = /["']\%functionStr\s*([\s\S]+)\s*functionStr\%["']/;

let fieldConfig = {};

function formItemFactory(formField, globalConfig, uiType) {
  const { wrapFormItemToken } = genTokenUtil(uiType);
  const { fieldProps, ...props } = formField;
  const field = {
    props: { ...fieldProps },
    ...props,
  };
  return {
    generator() {
      const fieldFactory = fieldConfig[field.type] ?? fieldConfig.input;
      const str = wrapFormItemToken(
        fieldFactory.code(field, globalConfig, { genCompPropStr }, uiType),
        field
      );
      return str;
    },
  };
}

function genQueryStr(store, fieldList) {
  const formData = {};
  let result = "";
  let row = [];
  const { wrapSearchFormToken } = genTokenUtil(store.uiType);
  for (let index = 0; index < fieldList.length; index++) {
    const field = fieldList[index];
    const fieldStr = formItemFactory(
      field,
      store.globalConfig,
      store.uiType
    ).generator();
    row.push(fieldStr + "\r\n");
    formData[field.formKey] = getFieldDefaultValue(field.type);
  }
  if (row.length > 0) {
    result += wrapSearchFormToken(row.join(""));
    row = [];
  }
  return {
    formTemplate: result,
    formData,
  };
}

function genColumn(store, field) {
  const { title, dataIndex, queryConfig, ...restProp } = field;
  const uiType = store.uiType;
  let column = {};
  if (uiType === "Element") {
    column = { label: title, prop: dataIndex, ...restProp };
    if (title === "序号") {
      delete column.customRender;
    }
  } else {
    column = {
      title,
      dataIndex,
      ...restProp,
    };
  }
  if (!isTableHelperColumn(title)) {
    delete column.width;
  }
  return column;
}

export async function genCode(
  templateFile,
  tableProps,
  fieldList,
  queryList,
  store
) {
  fieldConfig = getFieldConfig(store.uiType);

  const fileTemplate = await import(`../template/${templateFile}.vue?raw`);

  function visitField(fieldMap, fieldList) {
    for (const field of fieldList) {
      const { type, label, fieldList: subFieldList } = field;
      if (!isTableHelperColumn(label)) {
        if (type === "groupForm") {
          visitField(fieldMap, subFieldList);
        } else {
          fieldMap.push(genFieldMapField(field));
        }
      }
    }
  }

  const fieldMap = [];
  visitField(
    fieldMap,
    fieldList
      .filter((item) => item.title != "序号" && item.title != "操作")
      .map((item) => ({
        label: item.title,
        type: item.type || "input",
        key: item.dataIndex,
      }))
  );

  const finalQueryList = queryList.map(
    ({ isQuery, props, formKey, ...rest }) => {
      const query = {
        ...rest,
        searchFormKey: formKey,
      };
      if (props && Object.keys(props).length > 0) {
        query.fieldProps = props;
      }
      return query;
    }
  );

  const columns = fieldList
    .filter((column) => !column.hiddenInTable)
    .map(({ queryConfig, hiddenInTable, ...rest }) => genColumn(store, rest));

  // 生成自定义searchForm的表单代码和默认表单数据代码
  const { formTemplate, formData } = genQueryStr(store, queryList);

  let appVueStr =
    fileTemplate.default
      .replace("`%queryStr%`", formTemplate)
      .replace("`%queryFormData%`", JSON.stringify(formData))
      .replace("`%queryList%`", JSON.stringify(finalQueryList))
      .replace(
        "`%columns%`",
        JSON.stringify(columns, (_, value) =>
          typeof value === "function"
            ? `%functionStr ${value
                .toString()
                .replaceAll("\r", "")
                .replaceAll("\n", "")
                .replaceAll(/\s{3,}/g, " ")} functionStr%`
            : value
        )
      )
      .replace("`%tableProps%`", JSON.stringify(tableProps)) +
    `\r/** %fieldMap=${JSON.stringify(fieldMap)}% */`;

  const result = functionStrReg.exec(appVueStr);
  if (result) {
    appVueStr = appVueStr.replace(functionStrReg, result[1]);
  }

  return {
    "App.vue": appVueStr,
  };
}
